from logging import getLogger
from typing import BinaryIO, Optional, Union
from qcloud_cos import CosConfig, CosS3Client
from qcloud_cos.cos_exception import CosServiceError
from fastapi import UploadFile
from app.core.storage.base import BaseStorage

logger = getLogger(__name__)


class COSStorage(BaseStorage):
    """腾讯云COS存储实现"""

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 创建COS配置
        config = CosConfig(
            Region=self.region,
            SecretId=self.access_key,
            SecretKey=self.secret_key,
            Endpoint=self.endpoint if self.endpoint else None,
            Token=None,  # 如果使用临时密钥，需要传入Token
            Scheme="https",  # 指定使用 http/https 协议来访问 COS
        )
        # 创建客户端
        self.client = CosS3Client(config)

    async def save(self, file: Union[BinaryIO, UploadFile], filename: str) -> str:
        """保存文件到COS"""
        try:
            # 生成存储路径
            storage_path = self.generate_storage_path(filename)

            # 上传文件
            if isinstance(file, UploadFile):
                content = await file.read()
                self.client.put_object(
                    Bucket=self.bucket, Key=storage_path, Body=content, ContentType=self.get_content_type(filename)
                )
            else:
                self.client.put_object(
                    Bucket=self.bucket, Key=storage_path, Body=file, ContentType=self.get_content_type(filename)
                )

            return storage_path

        except CosServiceError as e:
            logger.error(f"COS上传失败: {str(e)}")
            raise Exception("文件上传失败")

    async def delete(self, file_path: str) -> bool:
        """从COS删除文件"""
        try:
            self.client.delete_object(Bucket=self.bucket, Key=file_path)
            return True
        except CosServiceError as e:
            logger.error(f"COS删除失败: {str(e)}")
            return False

    async def get(self, file_path: str) -> Optional[BinaryIO]:
        """从COS获取文件"""
        try:
            response = self.client.get_object(Bucket=self.bucket, Key=file_path)
            return response["Body"].get_raw_stream()
        except CosServiceError as e:
            logger.error(f"COS获取文件失败: {str(e)}")
            return None

    async def get_url(self, file_path: str, expires_in: int = 3600) -> str:
        """获取COS文件URL"""
        try:
            if self.base_url:
                return f"{self.base_url}/{file_path}"

            # 生成预签名URL
            url = self.client.get_presigned_url(Method="GET", Bucket=self.bucket, Key=file_path, Expired=expires_in)
            return url
        except CosServiceError as e:
            logger.error(f"生成URL失败: {str(e)}")
            raise Exception("生成文件访问URL失败")
